unit uRawRGBIO;

interface

uses Classes, RGSTextureStorage, GSPluginIntf;

type
  TRawRGBTexture = class(TRGSTextureStorage)
  public
    class function SupportBufferSize: cardinal; override;
    class function Supported(aStream: TStream): boolean; override;

    constructor Create(const W,H: word; F: TGSImageFormat; ML: byte); overload;
    function LoadFromStream(aStream: TStream): boolean; override;
    procedure SaveToStream(aStream: TStream); override;
  end;

implementation

uses uStreamUtils;

type
  TFileHeader = record
    cMagic: TMagic;
    wWidth,
    wHeight: word;
    bType,
    bMips: byte;
  end;

{ TRawRGBTexture }

constructor TRawRGBTexture.Create(const W, H: word; F: TGSImageFormat;
  ML: byte);
var i: integer;
    offs: cardinal;
begin
  inherited Create;

  FWidth := W;
  FHeight := H;
  FDepth := 1;
  FCubeMap := false;
  FFormat := F;

  FMips.bCount := ML;
  SetLength(fMips.aData, FMips.bCount);

  offs := 0;
  for i := 0 to pred(fMips.bCount) do begin
    fMips.aData[i].dwPos := offs;
    fMips.aData[i].FWidth := FWidth shr i;
    fMips.aData[i].FHeight := FHeight shr i;
    fMips.aData[i].FDataSize := fMips.aData[i].FWidth*fMips.aData[i].FHeight*sizeOf(TGSPixelQuad);
    inc(offs, fMips.aData[i].FDataSize);
  end;

  GetMem(FBits, DataSize);
end;

function TRawRGBTexture.LoadFromStream(aStream: TStream): boolean;
var i: integer;
    offs: cardinal;
    b: byte;
    s: TMagic;
    lData: PGSPixelQuad;
    hdr: TFileHeader;
begin
  result := false;
  aStream.Read(hdr, sizeOf(hdr));
  if (hdr.cMagic <> 'RRGB') then exit;

    FWidth := hdr.wWidth;
    FHeight := hdr.wHeight;
    FDepth := 1;
    FCubeMap := false;
    case hdr.bType of
      1: FFormat := gsifAlpha8;
      2: FFormat := gsifL8A8;
      3: FFormat := gsifRGB;
      4: FFormat := gsifRGBA;
    else
      exit;
    end;

    FMips.bCount := hdr.bMips;
    SetLength(fMips.aData, FMips.bCount);

    offs := 0;
    for i := 0 to pred(fMips.bCount) do begin
      fMips.aData[i].dwPos := offs;
      fMips.aData[i].FWidth := FWidth shr i;
      fMips.aData[i].FHeight := FHeight shr i;
      fMips.aData[i].FDataSize := fMips.aData[i].FWidth*fMips.aData[i].FHeight*sizeOf(TGSPixelQuad);
      inc(offs, fMips.aData[i].FDataSize);
    end;

  GetMem(FBits, DataSize);
  lData := FBits;
  for i := 0 to pred(DataSize div sizeOf(TGSPixelQuad)) do begin
    case FFormat of
      gsifAlpha8: begin
                    b := readByte(aStream);
                    lData^.r := b;
                    lData^.g := b;
                    lData^.b := b;
                    lData^.a := b;
                  end;
      gsifL8A8:   begin
                    b := readByte(aStream);
                    lData^.r := b;
                    lData^.g := b;
                    lData^.b := b;
                    lData^.a := readByte(aStream);
                  end;
      gsifRGB   : begin
                    lData^.r := readByte(aStream);
                    lData^.g := readByte(aStream);
                    lData^.b := readByte(aStream);
                    lData^.a := 255;
                  end;
      gsifRGBA  : begin
                    lData^.r := readByte(aStream);
                    lData^.g := readByte(aStream);
                    lData^.b := readByte(aStream);
                    lData^.a := readByte(aStream);
                  end;
    end;
    inc(lData);
  end;

  result := true;
end;

procedure writeRGB(r,g,b: byte; stream: TStream);
var buf: array[0..2] of byte;
begin
  buf[0] := r; buf[1] := g; buf[2] := b;
  stream.Write(buf, sizeOf(buf));
end;

procedure writeRGBA(buf: TGSPixelQuad; stream: TStream);
begin
  stream.Write(buf, sizeOf(buf));
end;

procedure TRawRGBTexture.SaveToStream(aStream: TStream);
var i: integer;
    lData: PGSPixelQuad;
    hdr: TFileHeader;
begin
  hdr.cMagic := 'RRGB';
  hdr.wWidth := FWidth;
  hdr.wHeight := FHeight;
  hdr.bType := byte(FFormat);
  hdr.bMips := FMips.bCount;
  aStream.Write(hdr, sizeOf(TFileHeader));

  lData := FBits;
  case FFormat of
    gsifAlpha8: for i := 0 to pred(DataSize div sizeOf(TGSPixelQuad)) do begin
                  writeByte(lData^.a, aStream);
                  inc(lData);
                end;
    gsifL8A8:   for i := 0 to pred(DataSize div sizeOf(TGSPixelQuad)) do begin
                  writeByte(round((lData^.r+lData^.g+lData^.b)/3), aStream);
                  writeByte(lData^.a, aStream);
                  inc(lData);
                end;
    gsifRGB   : for i := 0 to pred(DataSize div sizeOf(TGSPixelQuad)) do begin
                  writeRGB(lData^.r, lData^.g, lData^.b, aStream);
                  inc(lData);
                end;
    gsifRGBA  : begin
                  aStream.Write(lData^, DataSize);
                end;
    {
      for i := 0 to pred(DataSize div sizeOf(TGSPixelQuad)) do begin
                  writeRGBA(lData^, aStream);
                  inc(lData);
                end;}
  end;
end;

class function TRawRGBTexture.SupportBufferSize: cardinal;
begin
  result := sizeOf(TFileHeader);
end;

class function TRawRGBTexture.Supported(aStream: TStream): boolean;
var hdr: TFileHeader;
begin
  result := false;
  aStream.Read(hdr, sizeOf(TFileHeader));
  result := (hdr.cMagic = 'RRGB') and (hdr.bMips in [1..19]);
end;

end.
